package gm.editor;

import com.sun.scenario.scenegraph.JSGPanel;
import com.sun.scenario.scenegraph.SGGroup;
import com.sun.scenario.scenegraph.SGNode;
import com.sun.scenario.scenegraph.SGShape;
import com.sun.scenario.scenegraph.SGTransform;
import com.sun.scenario.scenegraph.event.SGMouseAdapter;
import gm.data.Hole;
import gm.data.HoleColor;
import gm.data.Kanava;
import gm.data.Stitch;
import gm.data.Wool;
import gm.editor.scripting.ScriptEditorFrame;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.EventListenerList;
import javax.swing.event.ListSelectionEvent;

/**
 * Kanava megjelenítő alaposztálya.
 *
 * @author imruf84
 */
public class KanavaPanel extends javax.swing.JPanel {

    /**
     * Események tárolója.
     */
    EventListenerList holeMouseListeners = new EventListenerList();
    EventListenerList stitchMouseListeners = new EventListenerList();

    /**
     * Parancsok.
     */
    public static final String COLOR_VIEW = "cv";
    public static final String STITCH_VIEW = "sv";
    public static final String CREATE_STITCH_ACTION = "cs";
    public static final String REVERSE_STITCH_ACTION = "rvs";
    public static final String REMOVE_STITCH_ACTION = "rms";

    /**
     * Kódszerkesztő ablak.
     */
    private ScriptEditorFrame codeWindow = null;

    /**
     * Kanava.
     */
    private Kanava kanava = null;
    /**
     * Kanava tárolója.
     */
    private final JSGPanel scenePanel = new JSGPanel();
    /**
     * Nagyítási faktor.
     */
    private final Point2D scale = new Point2D.Double(1, 0);
    /**
     * Eltolás mértéke.
     */
    private final Point2D translate = new Point2D.Double();
    /**
     * Kanava transzformációja.
     */
    private final SGTransform.Affine transformation = SGTransform.createAffine(null, null);
    /**
     * Nagyító csúszkája.
     */
    private DoubleJSlider zoomSlider = new DoubleJSlider(1, 10, 1, 1);
    /**
     * Jelenet tárolója.
     */
    private final SGGroup scene = new SGGroup();
    /**
     * Háttér.
     */
    private final SGShape backGroundNode = new SGShape();
    /**
     * Lyukak tárolója.
     */
    private final SGGroup holesNode = new SGGroup();
    /**
     * Fonalak tárolója.
     */
    private final SGGroup woolsNode = new SGGroup();
    /**
     * Fel nem használt öltések tárolója.
     */
    private final SGGroup stitchesNode = new SGGroup();
    /**
     * Fonalak tárolója.
     */
    private final HashMap<Character, WoolComponent> woolComponents = new HashMap<>();

    /**
     * Creates new form KanavaPanel
     *
     * @param kanava kanava
     * @param createComponents igaz esetén a kanava komponenseinek létrehozása
     * is megtörténik
     */
    @SuppressWarnings("unchecked")
    public KanavaPanel(final Kanava kanava, boolean createComponents) {

        this.kanava = kanava;

        initComponents();

        // Kódszerkesztő létrehozása.
        this.codeWindow = new ScriptEditorFrame(this);
        this.codeWindow.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                e.getWindow().setVisible(false);
                codeEditorToggleButton.setSelected(false);
            }
        });

        // Kódszerkesztő ablak frissítése.
        this.updateCodeEditorWindow();

        // Görgetés sebességének a meghatározása.
        this.optionsScrollPane.getHorizontalScrollBar().setUnitIncrement(EditorGUI.WHEEL_SCROLL_SIZE);
        this.optionsScrollPane.getVerticalScrollBar().setUnitIncrement(EditorGUI.WHEEL_SCROLL_SIZE);

        // Parancsok listájának létrehozása.
        // Színezés.
        JRadioButton colorizeButton = new JRadioButton("Színezés");
        colorizeButton.setActionCommand(KanavaPanel.COLOR_VIEW);
        colorizeButton.addActionListener((ActionEvent ae) -> {
            // Lyukak színezése módba váltunk.
            toColorizeHoleMode();
        });
        this.viewsPanel.add(colorizeButton);
        this.viewsGroup.add(colorizeButton);

        // Öltés.
        JRadioButton stitchButton = new JRadioButton("Öltés");
        stitchButton.setActionCommand(KanavaPanel.STITCH_VIEW);
        stitchButton.addActionListener((ActionEvent ae) -> {
            // Öltések módba váltunk.
            toStitchMode();
        });
        this.viewsPanel.add(stitchButton);
        viewsGroup.add(stitchButton);

        // Öltés létrehozása.
        JRadioButton stitchCreateButton = new JRadioButton("Öltés létrehozása");
        stitchCreateButton.setActionCommand(KanavaPanel.CREATE_STITCH_ACTION);
        stitchCreateButton.addActionListener((ActionEvent ae) -> {
            // Öltések létrehozása módba váltunk.
            toCreateStitchMode();
        });
        this.stitchesPanel.add(stitchCreateButton);
        stitchesGroup.add(stitchCreateButton);
        stitchCreateButton.setSelected(true);

        // Öltés irányának megfordítása.
        JRadioButton stitchReverseButton = new JRadioButton("Öltés megfordítása");
        stitchReverseButton.setActionCommand(KanavaPanel.REVERSE_STITCH_ACTION);
        stitchReverseButton.addActionListener((ActionEvent ae) -> {
            // Öltések létrehozása módba váltunk.
            toReverseStitchMode();
        });
        this.stitchesPanel.add(stitchReverseButton);
        stitchesGroup.add(stitchReverseButton);

        // Öltés irányának megfordítása.
        JRadioButton stitchRemoveButton = new JRadioButton("Öltés(ek) visszabontása");
        stitchRemoveButton.setActionCommand(KanavaPanel.REMOVE_STITCH_ACTION);
        stitchRemoveButton.addActionListener((ActionEvent ae) -> {
            // Öltések létrehozása módba váltunk.
            toRemoveStitchMode();
        });
        this.stitchesPanel.add(stitchRemoveButton);
        stitchesGroup.add(stitchRemoveButton);

        // Lyukak színezése módban kezdünk.
        colorizeButton.setSelected(true);
        this.toColorizeHoleMode();

        // Színek listájának létrehozása.
        this.colorsList.setCellRenderer(new HoleColorCellRenderer());

        zoomSlider.addChangeListener((javax.swing.event.ChangeEvent evt) -> {
            scale.setLocation(zoomSlider.getDoubleValue(), 0);
            updateTransformation();
        });
        zoomPanel.add(zoomSlider);

        // Rajzterület létrehozása.
        this.mainSplitPane.setLeftComponent(scenePanel);

        // Jelenet.
        this.scenePanel.setScene(this.transformation);
        this.transformation.setChild(this.scene);
        this.scene.add(this.holesNode);
        this.scene.add(this.woolsNode);
        this.scene.add(this.stitchesNode);

        // Nagyítás beállítása.
        this.scale.setLocation(this.zoomSlider.getDoubleValue(), 0);

        // Események.
        scenePanel.addComponentListener(new java.awt.event.ComponentAdapter() {
            @Override
            public void componentResized(java.awt.event.ComponentEvent evt) {
                updateTransformation();
            }
        });

        final Point2D dragFrom = new Point2D.Double();
        scenePanel.addMouseListener(new java.awt.event.MouseAdapter() {
            @Override
            public void mousePressed(java.awt.event.MouseEvent evt) {
                if (SwingUtilities.isMiddleMouseButton(evt)) {
                    scene.globalToLocal(evt.getPoint(), dragFrom);
                }
            }
        });
        scenePanel.addMouseMotionListener(
                new java.awt.event.MouseMotionAdapter() {
            @Override
            public void mouseDragged(java.awt.event.MouseEvent evt) {

                // Lekérjük a legközelebbi lyukat.
                Point2D p = new Point2D.Double();
                scene.globalToLocal(evt.getPoint(), p);
                List<SGNode> nl = scene.pick(p);
                nl.stream().filter((n) -> (n instanceof HoleComponent)).forEach((n) -> {
                    fireHoleMouseDragEvent(evt, (HoleComponent) n);
                });

                if (SwingUtilities.isMiddleMouseButton(evt)) {
                    Point2D dragTo = new Point2D.Double();
                    scene.globalToLocal(evt.getPoint(), dragTo);
                    Point2D dt = new Point2D.Double(dragTo.getX() - dragFrom.getX(), dragTo.getY() - dragFrom.getY());
                    translate.setLocation(translate.getX() + dt.getX(), translate.getY() + dt.getY());
                    updateTransformation();
                    scene.globalToLocal(evt.getPoint(), dragFrom);
                }
            }
        });
        scenePanel.addMouseWheelListener((java.awt.event.MouseWheelEvent evt) -> {
            if (evt.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) {
                double newScale = Math.max(zoomSlider.getDoubleMinimum(), Math.min(zoomSlider.getDoubleMaximum(), scale.getX() - (double) evt.getWheelRotation()));
                zoomSlider.setDoubleValue(newScale);
            }
        });

        if (createComponents) {
            this.createKanavaComponents();
        }

        // Lyukak egéreseményeinek a beállítása.
        this.addHoleMouseEventListener(new HoleMouseListener() {
            @Override
            public void mouseClicked(MouseEvent e, HoleComponent c) {

                if (SwingUtilities.isLeftMouseButton(e)) {
                    // Lyuk színezése.
                    if (isCurrentViewColor()) {
                        setHoleComponentColor(c, (HoleColor) colorsList.getSelectedValue());
                    }
                }
            }

            @Override
            public void mouseDragged(MouseEvent e, HoleComponent c) {
                if (SwingUtilities.isLeftMouseButton(e)) {
                    // Lyuk színezése.
                    if (isCurrentViewColor()) {
                        setHoleComponentColor(c, (HoleColor) colorsList.getSelectedValue());
                    }
                }
            }
        });

        // Öltések egéreseményeinek a beállítása.
        this.addStitchMouseEventListener((MouseEvent e, StitchComponent c) -> {
            // Bal gombbal kattintottunk.
            if (SwingUtilities.isLeftMouseButton(e)) {
                // Öltés létrehozása parancs.
                if (isCurrentActionCreateStitch()) {
                    // Aktuális fonal lekérdezése a kiválasztott szín alapján.
                    HoleColor color = (HoleColor) colorsList.getSelectedValue();
                    // Ha nincs szín kiválasztva, akkor kilépünk.
                    if (null == color) {
                        return;
                    }
                    // Egyébként lekérdezzük a színhez tartozó fonalat.
                    WoolComponent wc = getWoolComponent(color.getSymbol());
                    // Ha nem tartozik a színhez fonal, akkor kilépünk.
                    if (null == wc) {
                        return;
                    }
                    
                    // Ha a csomó már eleve a fonalhoz tartozik, akkor visszabontjuk és kilépünk.
                    if (wc.getWool().equals(c.getStitch().getWool())) {
                        
                        // Töröljük...
                        removeLastStitch(wc);
                        
                        // ...majd kilépünk.
                        return;
                    }

                    // Csomó hozzáadása a fonalhoz.
                    appendStitch(wc, c, true, true);
                }
                
                // Öltés irányának megfordítása parancs.
                if (isCurrentActionReverseStitch()) {
                    // Aktuális fonal lekérdezése a kiválasztott szín alapján.
                    HoleColor color = (HoleColor) colorsList.getSelectedValue();
                    // Ha nincs szín kiválasztva, akkor kilépünk.
                    if (null == color) {
                        return;
                    }
                    // Egyébként lekérdezzük a színhez tartozó fonalat.
                    WoolComponent wc = getWoolComponent(color.getSymbol());
                    // Ha nem tartozik a színhez fonal, akkor kilépünk.
                    if (null == wc) {
                        return;
                    }
                    
                    // Ha a csomó nem tartozik fonalhoz, akkor kilépünk.
                    if (null == c.getStitch().getWool()) {
                        return;
                    }
                    
                    reverseStitch(c, wc);
                }
                
                // Öltés visszabontása parancs.
                if (isCurrentActionRemoveStitch()) {
                    // Aktuális fonal lekérdezése a kiválasztott szín alapján.
                    HoleColor color = (HoleColor) colorsList.getSelectedValue();
                    // Ha nincs szín kiválasztva, akkor kilépünk.
                    if (null == color) {
                        return;
                    }
                    // Egyébként lekérdezzük a színhez tartozó fonalat.
                    WoolComponent wc = getWoolComponent(color.getSymbol());
                    // Ha nem tartozik a színhez fonal, akkor kilépünk.
                    if (null == wc) {
                        return;
                    }
                    
                    // Ha a csomó nem tartozik fonalhoz, akkor kilépünk.
                    if (null == c.getStitch().getWool()) {
                        return;
                    }
                    
                    // Csomó visszabontása.
                    c.removeFromWoolComponent(wc, stitchesNode, getKanava().getHoleColor(' '));
                    
                    // Kanava módosult.
                    getKanava().toModified();
                    
                    // HACK: - valamiért nem frissülnek a színek, ezért újrarajzolás szükséges
                    scenePanel.repaint();
                }
                
            }
        });

    }

    /**
     * Kódszerkesztő ablak frissítése.
     */
    public final void updateCodeEditorWindow() {
        this.codeWindow.updateTitle();
        this.codeWindow.setVisible(this.codeEditorToggleButton.isSelected());
    }

    /**
     * Kódszerkesztő ablak bezárása.
     */
    public void closeCodeEditorWindow() {
        this.codeWindow.dispose();
    }

    /**
     * Színek listájának frissítése.
     */
    @SuppressWarnings("unchecked")
    public void updateHoleColorsList() {
        // Színek felvétele a listába.
        DefaultListModel l = (DefaultListModel) this.colorsList.getModel();
        l.clear();
        for (Object c : this.kanava.getHoleColorSymbols()) {
            char symbol = (char) c;
            // Szín felvétele a listára.
            l.add(0, this.kanava.getHoleColor(symbol));
        }
    }

    /**
     * Fonal hozzáadása.
     *
     * @param symbol szín kódja
     * @return fonal
     */
    public WoolComponent addWoolComponent(char symbol) {
        // Fonal komponens létrehozása (a háttérhez nem tartozik fonal).
        if (' ' == symbol) {
            return null;
        }

        WoolComponent wc = this.woolComponents.get(symbol);

        // Ha még nem létezik ilyen fonal komponens, akkor létrehozzuk.
        if (null == wc) {
            wc = new WoolComponent(this.kanava.getWool(symbol));
            this.woolComponents.put(symbol, wc);
            this.woolsNode.add(wc);
        }

        return wc;

    }

    /**
     * Aktuális nézet lekérdezése.
     *
     * @return aktuális nézet.
     */
    public String getCurrentView() {
        return this.viewsGroup.getSelection().getActionCommand();
    }

    /**
     * Az aktuális nézet a színezés.
     *
     * @return igaz ha az aktuális nézet a színezés
     */
    public boolean isCurrentViewColor() {
        return this.getCurrentView().equals(KanavaPanel.COLOR_VIEW);
    }

    /**
     * Az aktuális nézet az öltés.
     *
     * @return igaz ha az aktuális nézet az öltés.
     */
    public boolean isCurrentViewStitch() {
        return this.getCurrentView().equals(KanavaPanel.STITCH_VIEW);
    }

    /**
     * Az aktuális parancs az öltés létrehozása.
     *
     * @return igaz ha az aktuális parancs az öltés létrehozása
     */
    public boolean isCurrentActionCreateStitch() {
        return this.isCurrentViewStitch()
                && this.stitchesGroup.getSelection().getActionCommand().equals(KanavaPanel.CREATE_STITCH_ACTION);
    }

    /**
     * Az aktuális parancs az öltés irányának fordítása.
     *
     * @return igaz ha az aktuális parancs az öltés irányának fordítása
     */
    public boolean isCurrentActionReverseStitch() {
        return this.isCurrentViewStitch()
                && this.stitchesGroup.getSelection().getActionCommand().equals(KanavaPanel.REVERSE_STITCH_ACTION);
    }

    /**
     * Az aktuális parancs az öltés visszabontására.
     *
     * @return igaz ha az aktuális parancs az öltés visszabontása
     */
    public boolean isCurrentActionRemoveStitch() {
        return this.isCurrentViewStitch()
                && this.stitchesGroup.getSelection().getActionCommand().equals(KanavaPanel.REMOVE_STITCH_ACTION);
    }

    /**
     * Kanava komponenseinek a létrehozása.
     */
    public final void createKanavaComponents() {

        this.updateHoleColorsList();

        // Háttér létrehozása.
        this.backGroundNode.setShape(new Rectangle2D.Double(
                -HoleComponent.OUTER_SIZE / 2 - (HoleComponent.OUTER_SIZE - HoleComponent.INNER_SIZE) / 2,
                -HoleComponent.OUTER_SIZE / 2 - (HoleComponent.OUTER_SIZE - HoleComponent.INNER_SIZE) / 2,
                this.kanava.getColumnsCount() * HoleComponent.OUTER_SIZE + (HoleComponent.OUTER_SIZE - HoleComponent.INNER_SIZE),
                this.kanava.getRowsCount() * HoleComponent.OUTER_SIZE + (HoleComponent.OUTER_SIZE - HoleComponent.INNER_SIZE)));
        this.backGroundNode.setFillPaint(Color.BLACK);
        this.scene.add(this.backGroundNode);
        this.scene.remove(this.holesNode);
        this.scene.add(this.holesNode);
        this.scene.remove(this.woolsNode);
        this.scene.add(this.woolsNode);
        this.scene.remove(this.stitchesNode);
        this.scene.add(this.stitchesNode);

        // Lyukak kirajzolása.
        // Összes lépés számának a meghatározása.
        int all = this.kanava.getRowsCount() * this.kanava.getColumnsCount();
        for (Object c : this.kanava.getHoleColorSymbols()) {
            char symbol = (char) c;
            Wool w = this.kanava.getWool(symbol);

            if (null == w) {
                continue;
            }

            all += w.size();
        }

        // Kezdődhet a munka.
        int created = 0;
        for (int r = 0; r < this.kanava.getRowsCount(); r++) {
            for (int c = 0; c < this.kanava.getColumnsCount(); c++) {

                // Lyuk létrehozása.
                HoleComponent hc = new HoleComponent(this.kanava.getHole(r, c));
                this.holesNode.add(hc);

                // Események.
                hc.addMouseListener(new SGMouseAdapter() {
                    @Override
                    public void mouseEntered(MouseEvent e, SGNode n) {
                        Hole h = ((HoleComponent) n).getHole();
                        coordinatesLabel.setText(" Sor:" + (h.getRow() + 1) + " Oszlop:" + (h.getColumn() + 1));
                    }

                    @Override
                    public void mouseClicked(MouseEvent e, SGNode n) {
                        HoleComponent hc = (HoleComponent) n;

                        boolean pickInnerHole = hc.getInnerHoleShape().getTransformedBounds().contains(e.getPoint());

                        // Belső lyukra kattintottunk.
                        if (pickInnerHole) {
                            fireHoleMouseClickEvent(e, hc);
                        }
                    }
                });

                // Öltés létrehozása.
                Stitch st = this.kanava.getStitch(r, c);
                if (!(null == st)) {
                    StitchComponent sc = new StitchComponent(st, this.getKanava().getHoleColor(' ').getColor());
                    this.stitchesNode.add(sc);

                    // Események.
                    sc.addMouseListener(new SGMouseAdapter() {
                        @Override
                        public void mouseClicked(MouseEvent e, SGNode n) {
                            StitchComponent sc = (StitchComponent) n;

                            boolean pickMasterControl = sc.getMasterControlShape().getTransformedBounds().contains(e.getPoint());

                            // Belső lyukra kattintottunk.
                            if (pickMasterControl) {
                                fireStitchMouseClickEvent(e, sc);
                            }
                        }
                    });

                }

                // Esemény futtatása.
                if (!this.updateCreation(all, ++created)) {
                    return;
                }
            }
        }

        // Fonalak létrehozása.
        for (Object c : this.kanava.getHoleColorSymbols()) {
            char symbol = (char) c;
            WoolComponent wc = this.addWoolComponent(symbol);

            if (null == wc) {
                continue;
            }

            // Öltések hozzáadása a fonalhoz.
            for (Object sto : wc.getWool().toArray()) {
                Stitch st = (Stitch) sto;
                StitchComponent sc = this.getStitchComponent(st.getRow(), st.getColumn(), true, false);
                sc.addToWoolComponent(wc, false, false);

                // Esemény futtatása.
                if (!this.updateCreation(all, ++created)) {
                    return;
                }
            }
        }

        // Kanava középre helyezése.
        this.translate.setLocation(
                -this.kanava.getColumnsCount() * HoleComponent.OUTER_SIZE / 2 + HoleComponent.OUTER_SIZE / 2,
                -this.kanava.getRowsCount() * HoleComponent.OUTER_SIZE / 2 + HoleComponent.OUTER_SIZE / 2);
    }

    /**
     * Lyuk komponens lekérdezése.
     *
     * @param row sor
     * @param column oszlop
     * @return lyuk komponens
     */
    public HoleComponent getHoleComponent(int row, int column) {

        Kanava k = this.getKanava();
        if ((row > k.getRowsCount() - 1) || (column > k.getColumnsCount() - 1)) {
            return null;
        }

        for (SGNode n : this.holesNode.getChildren()) {
            HoleComponent hc = (HoleComponent) n;
            if ((hc.getHole().getRow() == row) && (hc.getHole().getColumn() == column)) {
                return hc;
            }
        }

        return null;
    }

    /**
     * Szkript forráskódjának megadása.
     *
     * @param script szkript forráskódja
     */
    public void setScriptSourceCode(String script) {
        this.codeWindow.setSourceCode(script);
    }

    /**
     * Szkript forráskódjának a lekérdezése.
     *
     * @return szkript forráskódja
     */
    public String getScriptSourceCode() {
        return this.codeWindow.getSourceCode();
    }

    /**
     * Lyukak tömbjének lekérdezése.
     *
     * @return lyukak tömbje
     */
    public HoleComponent[] getHoleComponents() {
        LinkedList<HoleComponent> hl = new LinkedList<>();
        this.holesNode.getChildren().stream().forEach((n) -> {
            hl.add((HoleComponent) n);
        });

        return (HoleComponent[]) hl.toArray();
    }

    /**
     * Lyuk komponens színének megadása.
     *
     * @param hc lyuk komponens
     * @param hcolor új szín
     */
    public void setHoleComponentColor(HoleComponent hc, HoleColor hcolor) {
        hc.setHoleColor(hcolor);
        kanava.toModified();
    }

    /**
     * Öltés lekérdezése.
     *
     * @param row sor
     * @param column oszlop
     * @param findInUnused igaz esetén a fel nem használtak közt lesz a keresés
     * @param findInWools igaz esetén a fonalak is végig lesznek vizsgálva, nem
     * csak a gazdátlan öltések
     * @return öltés
     */
    public StitchComponent getStitchComponent(int row, int column, boolean findInUnused, boolean findInWools) {
        // A gazdátlan öltésekkel kezdjük.
        if (findInUnused) {
            for (SGNode n : this.stitchesNode.getChildren()) {
                StitchComponent st = (StitchComponent) n;
                if ((st.getStitch().getRow() == row) && (st.getStitch().getColumn() == column)) {
                    return st;
                }
            }
        }

        // Majd a fonalak öltéseivel folytatjuk.
        if (findInWools) {
            for (WoolComponent wc : this.woolComponents.values()) {
                for (StitchComponent sc : wc.getStitchComponents()) {
                    if ((sc.getStitch().getRow() == row) && (sc.getStitch().getColumn() == column)) {
                        return sc;
                    }
                }
            }
        }

        return null;
    }

    /**
     * Adott színű lyukak színének frissítése.
     *
     * @param symbol szín szimbóluma
     */
    public void updateHolesColor(char symbol) {

        // Lyukak színének a frissítése.
        Iterator<SGNode> it = this.holesNode.getChildren().iterator();
        while (it.hasNext()) {
            SGNode n = it.next();
            if (n instanceof HoleComponent) {
                HoleComponent hc = (HoleComponent) n;
                if (symbol == hc.getHole().getHoleColor().getSymbol()) {
                    hc.setHoleColor(this.kanava.getHoleColor(symbol));
                }
            }
        }

        // Háttér színének módosítása a még fel nem használt öltések színének módosítását és a rács kontúrjának színezését is eredményezi.
        if (' ' == symbol) {
            Color newColor = this.getKanava().getHoleColor(symbol).getColor();
            // Háttér rácsozatának a színezése.
            this.backGroundNode.setFillPaint(HoleComponent.getContrastColor(newColor));
            // Fel nem használt öltések színezése.
            it = this.stitchesNode.getChildren().iterator();
            while (it.hasNext()) {
                SGNode n = it.next();
                if (n instanceof StitchComponent) {
                    StitchComponent sc = (StitchComponent) n;
                    // Ha az öltés még nem tartozik egyetlen fonalhoz sem, akkor módosítjuk.
                    if (null == sc.getStitch().getWool()) {
                        sc.colorizeControlShape(newColor);
                    }
                }
            }
        } else {
            // Egyébként fonal színéhez tartozó öltéseket módosítunk a fonallal együtt.
            WoolComponent wc = this.getWoolComponent(symbol);
            Iterator<StitchComponent> it2 = wc.getStitchComponents().iterator();
            while (it2.hasNext()) {
                SGNode n = it2.next();
                if (n instanceof StitchComponent) {
                    StitchComponent sc = (StitchComponent) n;
                    sc.colorizeControlShape(this.getKanava().getHoleColor(symbol).getColor());
                }
            }

            // Valamint a fonal színét is frissítjük.
            wc.updateWoolColor();
        }

    }

    /**
     * Szín lecserélése.
     *
     * @param c1 milyen színt
     * @param c2 milyen színre
     */
    public void changeHoleColors(char c1, char c2) {

        // Lyukak.
        Iterator<SGNode> it = this.holesNode.getChildren().iterator();
        while (it.hasNext()) {
            SGNode n = it.next();
            if (n instanceof HoleComponent) {
                HoleComponent hc = (HoleComponent) n;
                if (c1 == hc.getHole().getHoleColor().getSymbol()) {
                    hc.setHoleColor(this.kanava.getHoleColor(c2));
                }
            }
        }

        // Ha a háttérszínre cserélünk akkor töröljük az adott színhez tartozó fonalat.
        if (' ' == c2) {
            WoolComponent wc = this.getWoolComponent(c1);
            Iterator<StitchComponent> it2 = wc.getStitchComponents().iterator();
            // Lyukak visszahelyezése.
            while (it2.hasNext()) {
                StitchComponent sc = it2.next();
                this.stitchesNode.add(sc);
                sc.getStitch().addToWool(null);
                sc.colorizeControlShape(this.getKanava().getHoleColor(c2).getColor());
            }

            // Fonal eltávolítása.
            this.woolComponents.remove(c1);
            this.woolsNode.remove(wc);
        }
    }

    /**
     * Komponensek létrehozásának frissítése.
     *
     * @param all összes komponensek száma
     * @param created létrehozott komponensek száma
     * @return hamis esetén leáll a létrehozás
     */
    public boolean updateCreation(int all, int created) {
        return true;
    }

    /**
     * Transzformációs mátrix frissítése.
     */
    private void updateTransformation() {
        AffineTransform at = new AffineTransform();
        at.translate(this.scenePanel.getWidth() / 2, this.scenePanel.getHeight() / 2);
        at.scale(this.scale.getX(), this.scale.getX());
        at.translate(this.translate.getX(), this.translate.getY());
        this.transformation.setAffine(at);
    }

    /**
     * Kanava lekérdezése.
     *
     * @return kanava
     */
    public Kanava getKanava() {
        return this.kanava;
    }

    /**
     * Fonal komponens lekérdezése szín azonosító alapján.
     *
     * @param symbol szín azonosítója
     * @return fonal komponens
     */
    public WoolComponent getWoolComponent(char symbol) {
        return this.woolComponents.get(symbol);
    }

    /**
     * Öltés hozzáadása fonalhoz.
     *
     * @param wc fonal
     * @param sc öltés
     * @param autoReverse igaz esetén automatikusan meghatározza az optimális
     * irányt
     * @param addToWool igaz esetén tárolva lesz a fonalban is
     */
    public void appendStitch(WoolComponent wc, StitchComponent sc, boolean autoReverse, boolean addToWool) {

        // Öltés tárolása.
        sc.addToWoolComponent(wc, autoReverse, addToWool);

        // Kanava módosult.
        getKanava().toModified();

        // HACK: - valamiért nem frissülnek a színek, ezért újrarajzolás szükséges
        scenePanel.repaint();
    }

    /**
     * Öltés irányának megfordítása.
     *
     * @param sc öltés
     * @param wc fonal
     */
    public void reverseStitch(StitchComponent sc, WoolComponent wc) {

        // Csomó irányának megfordítása.
        sc.reverse(wc);

        // Kanava módosult.
        getKanava().toModified();

        // HACK: - valamiért nem frissülnek a színek, ezért újrarajzolás szükséges
        scenePanel.repaint();
    }

    /**
     * Fonal utolsó öltésének az eltávolítása.
     *
     * @param wc fonal
     */
    public void removeLastStitch(WoolComponent wc) {

        // Előző öltés lekérdezése.
        StitchComponent scp = wc.getBeforeLastStitchComponent();

        // Ha nem létezik, akkor a jelenlegit töröljük (mivel már csak ő van egyedül).
        if (null == scp) {
            scp = wc.getLastStitchComponent();
        }

        // Egyébként visszabontjuk a csomót.
        scp.removeFromWoolComponent(wc, stitchesNode, getKanava().getHoleColor(' '));

        // Kanava módosult.
        getKanava().toModified();

        // HACK: - valamiért nem frissülnek a színek, ezért újrarajzolás szükséges
        scenePanel.repaint();
    }

    /**
     * Lyuk egéreseményének tárolása.
     *
     * @param l
     */
    public final void addHoleMouseEventListener(HoleMouseListener l) {
        this.holeMouseListeners.add(HoleMouseListener.class, l);
    }

    /**
     * Lyuk egéreseményének az eltávolítása.
     *
     * @param l
     */
    public void removeHoleMouseEventListener(HoleMouseListener l) {
        this.holeMouseListeners.remove(HoleMouseListener.class, l);
    }

    /**
     * Lyukra kattintás egér eseményének hívása.
     *
     * @param e egéresemény
     * @param c lyuk objektum
     */
    protected void fireHoleMouseClickEvent(MouseEvent e, HoleComponent c) {
        Object[] listeners = this.holeMouseListeners.getListenerList();

        int n = listeners.length;
        for (int i = 0; i < n; i += 2) {
            if (listeners[i] == HoleMouseListener.class) {
                ((HoleMouseListener) listeners[i + 1]).mouseClicked(e, c);
            }
        }
    }

    /**
     * Lyukon vonszolás eseménye.
     *
     * @param e egéresemény
     * @param c lyuk komponens
     */
    protected void fireHoleMouseDragEvent(MouseEvent e, HoleComponent c) {
        Object[] listeners = this.holeMouseListeners.getListenerList();

        int n = listeners.length;
        for (int i = 0; i < n; i += 2) {
            if (listeners[i] == HoleMouseListener.class) {
                ((HoleMouseListener) listeners[i + 1]).mouseDragged(e, c);
            }
        }
    }

    /**
     * Öltés egéreseményének tárolása.
     *
     * @param l
     */
    public final void addStitchMouseEventListener(StitchMouseListener l) {
        this.stitchMouseListeners.add(StitchMouseListener.class, l);
    }

    /**
     * Öltés egéreseményének az eltávolítása.
     *
     * @param l
     */
    public void removeStitchMouseEventListener(StitchMouseListener l) {
        this.stitchMouseListeners.remove(StitchMouseListener.class, l);
    }

    /**
     * Öltés fő vezérlőjére kattintás egér eseményének hívása.
     *
     * @param e egéresemény
     * @param c öltés objektum
     */
    protected void fireStitchMouseClickEvent(MouseEvent e, StitchComponent c) {
        Object[] listeners = this.stitchMouseListeners.getListenerList();

        int n = listeners.length;
        for (int i = 0; i < n; i += 2) {
            if (listeners[i] == StitchMouseListener.class) {
                ((StitchMouseListener) listeners[i + 1]).mouseClicked(e, c);
            }
        }
    }

    /**
     * Lyuk színezése módba váltás.
     */
    public final void toColorizeHoleMode() {
        // Nem jelenítjük meg az öltéseket.
        this.stitchesNode.setVisible(false);
        this.woolsNode.setVisible(false);
        this.stitchesPanel.setVisible(false);
    }

    /**
     * Öltések létrehozása módba váltás.
     */
    public void toStitchMode() {
        // Megjelenítjük az öltéseket.
        this.stitchesNode.setVisible(true);
        this.woolsNode.setVisible(true);
        this.stitchesPanel.setVisible(true);

        this.changeStitchAction(this.stitchesGroup.getSelection().getActionCommand());
    }

    /**
     * Öltés létrehozása módba váltás.
     */
    public void toCreateStitchMode() {
        this.stitchesNode.setVisible(true);
        Iterator<WoolComponent> it = this.woolComponents.values().iterator();
        while (it.hasNext()) {
            WoolComponent wc = it.next();
            wc.setStitchesVisible(false);
            wc.getLastStitchNode().setVisible(true);
        }
        // Frissítünk a kijelölt szín alapján.
        colorsListValueChanged(new ListSelectionEvent(new Object(), 0, 0, false));
    }

    /**
     * Öltés irányának a megfordítása módba váltás.
     */
    public void toReverseStitchMode() {
        this.stitchesNode.setVisible(false);
        Iterator<WoolComponent> it = this.woolComponents.values().iterator();
        while (it.hasNext()) {
            WoolComponent wc = it.next();
            wc.setStitchesVisible(true);
            wc.getLastStitchNode().setVisible(true);
        }
        // Frissítünk a kijelölt szín alapján.
        colorsListValueChanged(new ListSelectionEvent(new Object(), 0, 0, false));
    }

    /**
     * Öltés visszabontása módba váltás.
     */
    public void toRemoveStitchMode() {
        this.stitchesNode.setVisible(false);
        Iterator<WoolComponent> it = this.woolComponents.values().iterator();
        while (it.hasNext()) {
            WoolComponent wc = it.next();
            wc.setStitchesVisible(true);
            wc.getLastStitchNode().setVisible(true);
        }
        // Frissítünk a kijelölt szín alapján.
        colorsListValueChanged(new ListSelectionEvent(new Object(), 0, 0, false));
    }

    /**
     * Jelenlegi parancs frissítése.
     */
    public void updateAction() {
        if (this.isCurrentViewColor()) {
            this.toColorizeHoleMode();
            return;
        }

        if (this.isCurrentViewStitch()) {
            this.changeStitchAction(this.stitchesGroup.getSelection().getActionCommand());
        }
    }

    /**
     * Öltéssel kapcsolatos parancs váltása.
     *
     * @param action parancs
     */
    public void changeStitchAction(String action) {
        switch (action) {
            case KanavaPanel.CREATE_STITCH_ACTION:
                this.toCreateStitchMode();
                break;
            case KanavaPanel.REVERSE_STITCH_ACTION:
                this.toReverseStitchMode();
                break;
            case KanavaPanel.REMOVE_STITCH_ACTION:
                this.toRemoveStitchMode();
                break;
        }
    }

    /**
     * Új szín hozzáadása / meglévő módosítása.
     *
     * @param hc szín
     * @param select igaz esetén az új szín ki lesz jelölve
     * @param update igaz esetén frissülnek a szerkesztő egyéb dolgai is
     */
    public void addHoleColor(HoleColor hc, boolean select, boolean update) {
        HoleColor lhc = this.kanava.addHoleColor(hc);
        this.addWoolComponent(lhc.getSymbol());
        this.updateHoleColorsList();
        if (select) {
            this.colorsList.setSelectedValue(lhc, true);
        }
        this.updateHolesColor(lhc.getSymbol());
        if (update) {
            this.updateAction();
        }
    }

    /**
     * Szín törlése.
     *
     * @param hc szín
     * @param index szín sorszáma alistán (igaz select esetén van jelentősége)
     * @param select igaz esetén új szín lesz kijelölve
     */
    public void removeHoleColor(HoleColor hc, int index, boolean select) {
        if (this.kanava.removeHoleColor(hc.getSymbol())) {
            this.updateHoleColorsList();
            this.changeHoleColors(hc.getSymbol(), ' ');
            if (select) {
                this.colorsList.setSelectedIndex(
                        Math.min(index, ((DefaultListModel) this.colorsList.getModel()).getSize() - 1));
            }
            this.updateHolesColor(' ');
        }
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        viewsGroup = new javax.swing.ButtonGroup();
        stitchesGroup = new javax.swing.ButtonGroup();
        mainSplitPane = new javax.swing.JSplitPane();
        optionsScrollPane = new javax.swing.JScrollPane();
        optionsPanel = new javax.swing.JPanel();
        colorsPanel = new javax.swing.JPanel();
        colorsListScrollPane = new javax.swing.JScrollPane();
        colorsList = new javax.swing.JList();
        colorButtonsPanel = new javax.swing.JPanel();
        addColorButton = new javax.swing.JButton();
        removeColorButton = new javax.swing.JButton();
        viewsPanel = new javax.swing.JPanel();
        stitchesPanel = new javax.swing.JPanel();
        scriptingPanel = new javax.swing.JPanel();
        codeEditorToggleButton = new javax.swing.JToggleButton();
        informationPanel = new javax.swing.JPanel();
        zoomPanel = new javax.swing.JPanel();
        zoomLabel = new javax.swing.JLabel();
        coordinatesLabel = new javax.swing.JLabel();

        setMinimumSize(new java.awt.Dimension(190, 120));
        setPreferredSize(new java.awt.Dimension(255, 160));
        setLayout(new java.awt.BorderLayout());

        mainSplitPane.setResizeWeight(1.0);
        mainSplitPane.setLastDividerLocation(-1);

        optionsScrollPane.setBorder(null);
        optionsScrollPane.setMinimumSize(new java.awt.Dimension(170, 100));

        optionsPanel.setPreferredSize(new java.awt.Dimension(160, 137));

        colorsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Színek"));
        colorsPanel.setLayout(new java.awt.BorderLayout());

        colorsList.setModel(new DefaultListModel()
        );
        colorsList.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                colorsListMouseClicked(evt);
            }
        });
        colorsList.addListSelectionListener(new javax.swing.event.ListSelectionListener() {
            public void valueChanged(javax.swing.event.ListSelectionEvent evt) {
                colorsListValueChanged(evt);
            }
        });
        colorsListScrollPane.setViewportView(colorsList);

        colorsPanel.add(colorsListScrollPane, java.awt.BorderLayout.CENTER);

        addColorButton.setText("Új szín...");
        addColorButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                addColorButtonActionPerformed(evt);
            }
        });
        colorButtonsPanel.add(addColorButton);

        removeColorButton.setText("Töröl");
        removeColorButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                removeColorButtonActionPerformed(evt);
            }
        });
        colorButtonsPanel.add(removeColorButton);

        colorsPanel.add(colorButtonsPanel, java.awt.BorderLayout.PAGE_END);

        viewsPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Nézet"));
        viewsPanel.setLayout(new javax.swing.BoxLayout(viewsPanel, javax.swing.BoxLayout.PAGE_AXIS));

        stitchesPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Öltések kezelése"));
        stitchesPanel.setLayout(new javax.swing.BoxLayout(stitchesPanel, javax.swing.BoxLayout.PAGE_AXIS));

        scriptingPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Szkriptelés"));
        scriptingPanel.setLayout(new java.awt.GridLayout(1, 0));

        codeEditorToggleButton.setMnemonic(KeyEvent.VK_P);
        codeEditorToggleButton.setText("Kódszerkesztő...");
        codeEditorToggleButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                codeEditorToggleButtonActionPerformed(evt);
            }
        });
        scriptingPanel.add(codeEditorToggleButton);

        javax.swing.GroupLayout optionsPanelLayout = new javax.swing.GroupLayout(optionsPanel);
        optionsPanel.setLayout(optionsPanelLayout);
        optionsPanelLayout.setHorizontalGroup(
            optionsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(colorsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)
            .addComponent(viewsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 170, Short.MAX_VALUE)
            .addComponent(stitchesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
            .addComponent(scriptingPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        );
        optionsPanelLayout.setVerticalGroup(
            optionsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(optionsPanelLayout.createSequentialGroup()
                .addComponent(viewsPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(stitchesPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(scriptingPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(colorsPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 79, Short.MAX_VALUE))
        );

        optionsScrollPane.setViewportView(optionsPanel);

        mainSplitPane.setRightComponent(optionsScrollPane);

        add(mainSplitPane, java.awt.BorderLayout.CENTER);

        informationPanel.setLayout(new javax.swing.BoxLayout(informationPanel, javax.swing.BoxLayout.LINE_AXIS));

        zoomPanel.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.LOWERED));
        zoomPanel.setMaximumSize(new java.awt.Dimension(200, 24));
        zoomPanel.setLayout(new javax.swing.BoxLayout(zoomPanel, javax.swing.BoxLayout.LINE_AXIS));

        zoomLabel.setText(" Nagyítás: ");
        zoomPanel.add(zoomLabel);

        informationPanel.add(zoomPanel);

        coordinatesLabel.setText("- x -");
        informationPanel.add(coordinatesLabel);

        add(informationPanel, java.awt.BorderLayout.PAGE_END);
    }// </editor-fold>//GEN-END:initComponents

    private void addColorButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addColorButtonActionPerformed
        final JPanel p = new JPanel(new GridLayout(0, 2));

        JTextField symbolField = new JTextField(1);
        symbolField.addFocusListener(new FocusAdapter() {
            @Override
            public void focusGained(final FocusEvent e) {
                SwingUtilities.invokeLater(() -> {
                    JTextField tf = (JTextField) e.getSource();
                    tf.selectAll();
                });
            }
        });
        symbolField.setDocument(new LengthRestrictedDocument(1));
        p.add(new JLabel("Szimbólum:"));
        p.add(symbolField);

        final JColorChooser colorChooser = new JColorChooser();
        final JButton colorButton = new JButton(new ColorIcon(32, 16, Color.WHITE));
        colorButton.addActionListener((ActionEvent ae) -> {
            JDialog dialog = JColorChooser.createDialog(p.getParent(),
                    "Szín választása", false, colorChooser, (ActionEvent event) -> {
                        colorButton.setIcon(new ColorIcon(32, 16, colorChooser.getColor()));
            }, (ActionEvent event) -> {
                // Mégsem...
            });
            dialog.setModal(true);
            dialog.setVisible(true);
        });
        p.add(new JLabel("Szín:"));
        p.add(colorButton);

        // Ha van szín kijelölve, akkor az lesz a kezdeti érték.
        if (!(0 > this.colorsList.getSelectedIndex())) {
            HoleColor hc = (HoleColor) this.colorsList.getSelectedValue();
            colorChooser.setColor(hc.getColor());
            colorButton.setIcon(new ColorIcon(32, 16, hc.getColor()));
            symbolField.setText(hc.getSymbol() + "");
        }

        Object[] o = {"Létrehoz", "Mégsem"};
        int n = JOptionPane.showOptionDialog(
                this,
                p,
                "Szín létrehozása",
                JOptionPane.YES_NO_OPTION,
                JOptionPane.DEFAULT_OPTION,
                null, o, symbolField);

        if (JOptionPane.YES_OPTION == n) {
            if (!(0 < symbolField.getText().length())) {
                JOptionPane.showMessageDialog(this, "Szimbólum megadása kötelező!", "Hiba", JOptionPane.ERROR_MESSAGE, null);
                return;
            }

            this.addHoleColor(new HoleColor(colorChooser.getColor(), symbolField.getText().charAt(0)), true, true);
        }
    }//GEN-LAST:event_addColorButtonActionPerformed

    private void removeColorButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeColorButtonActionPerformed

        int index = colorsList.getSelectedIndex();

        // Ha nincs szín kijelölve akkor kilépünk.
        if (0 > index) {
            return;
        }

        // Egyébként töröljük a kijelölt színt.
        HoleColor hc = (HoleColor) colorsList.getSelectedValue();
        this.removeHoleColor(hc, index, true);
    }//GEN-LAST:event_removeColorButtonActionPerformed

    private void colorsListMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_colorsListMouseClicked
        // Kijelölt szín módosítása.
        if (evt.getClickCount() == 2) {
            addColorButtonActionPerformed(null);
        }
    }//GEN-LAST:event_colorsListMouseClicked

    private void colorsListValueChanged(javax.swing.event.ListSelectionEvent evt) {//GEN-FIRST:event_colorsListValueChanged

        // Minden fonalat eltüntetünk.
        Iterator<WoolComponent> it = this.woolComponents.values().iterator();
        while (it.hasNext()) {
            WoolComponent lwc = it.next();
            lwc.getAllStitchesNode().setVisible(false);
            lwc.getBackWoolNode().setVisible(false);
        }

        // Színnek megfelelő fonal csomópontjainak a kijelölése.
        HoleColor hc = (HoleColor) (this.colorsList.getSelectedValue());
        if ((null != hc) && !evt.getValueIsAdjusting()) {
            WoolComponent wc = this.getWoolComponent(hc.getSymbol());
            if (null == wc) {
                return;
            }
            wc.getAllStitchesNode().setVisible(true);
            wc.getBackWoolNode().setVisible(true);
            // A kijelölt fonalat helyezzük legfelülre.
            this.woolsNode.remove(wc);
            this.woolsNode.add(wc);
        }
    }//GEN-LAST:event_colorsListValueChanged

    private void codeEditorToggleButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_codeEditorToggleButtonActionPerformed
        this.updateCodeEditorWindow();
    }//GEN-LAST:event_codeEditorToggleButtonActionPerformed


    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton addColorButton;
    private javax.swing.JToggleButton codeEditorToggleButton;
    private javax.swing.JPanel colorButtonsPanel;
    private javax.swing.JList colorsList;
    private javax.swing.JScrollPane colorsListScrollPane;
    private javax.swing.JPanel colorsPanel;
    private javax.swing.JLabel coordinatesLabel;
    private javax.swing.JPanel informationPanel;
    private javax.swing.JSplitPane mainSplitPane;
    private javax.swing.JPanel optionsPanel;
    private javax.swing.JScrollPane optionsScrollPane;
    private javax.swing.JButton removeColorButton;
    private javax.swing.JPanel scriptingPanel;
    private javax.swing.ButtonGroup stitchesGroup;
    private javax.swing.JPanel stitchesPanel;
    private javax.swing.ButtonGroup viewsGroup;
    private javax.swing.JPanel viewsPanel;
    private javax.swing.JLabel zoomLabel;
    private javax.swing.JPanel zoomPanel;
    // End of variables declaration//GEN-END:variables
}
